package juc.atomic;

import sun.misc.Unsafe;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.HashSet;
import java.util.Set;

public class UnsafeFooTest {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException, NoSuchFieldException, IOException, NoSuchMethodException, InvocationTargetException {
        //Simple simple = new Simple();
        //System.out.println(simple.get());

        //Simple simple=Simple.class.newInstance();//会做类的初始化

        //Class.forName("jcu.atomic.UnsafeFooTest$Simple");//不会导致类的初始化


        Unsafe unsafe = getUnsafe();//绕过初始化，直接开辟内存
        //Simple simple = (Simple) unsafe.allocateInstance(Simple.class);
        //System.out.println(simple.get());
        //System.out.println(simple.getClass());
        //System.out.println(simple.getClass().getClassLoader());

        //Guard guard = new Guard();
        //guard.work();
        //Field f = guard.getClass().getDeclaredField("ACCESS_ALLOWED");
        //unsafe.putInt(guard, unsafe.objectFieldOffset(f), 42);
        //guard.work();

        //byte[] bytes = loadClassCounter();
        //Class aClass = unsafe.defineClass(null, bytes, 0, bytes.length);
        //int v = (Integer) aClass.getMethod("get").invoke(aClass.newInstance(), null);
        //System.out.println(v);

        System.out.println(sizeOf(new Simple()));
    }

    private static long sizeOf(Object obj) {
        Unsafe unsafe = getUnsafe();
        Set<Field> fields = new HashSet<>();
        Class c = obj.getClass();
        while (c != Object.class) {
            Field[] declaredFields = c.getDeclaredFields();
            for (Field f : declaredFields) {
                if ((f.getModifiers() & Modifier.STATIC) == 0) {
                    fields.add(f);
                }
            }
            c = c.getSuperclass();
        }
        long maxOffSet = 0;
        for (Field f : fields) {
            long offset = unsafe.objectFieldOffset(f);
            if (offset > maxOffSet) {
                maxOffSet = offset;
            }
        }
        return ((maxOffSet / 8) + 1) * 8;
    }

    private static byte[] loadClassCounter() throws IOException {
        File f = new File("D:\\IdeaProjects\\concurrency\\jcuexample\\target\\classes\\A.class");
        FileInputStream fis = new FileInputStream(f);
        byte[] content = new byte[(int) f.length()];
        fis.read(content);
        fis.close();
        return content;
    }

    static class Guard {
        private int ACCESS_ALLOWED = 1;

        private boolean allow() {
            return 42 == ACCESS_ALLOWED;
        }

        public void work() {
            if (allow()) {
                System.out.println("I am working by allowed");
            }
        }
    }

    private static Unsafe getUnsafe() {
        try {
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            return (Unsafe) f.get(null);//这里是static用null
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    static class Simple {
        private long l = 0;

        public Simple() {
            this.l = 1;
            System.out.println("====");
        }

        public long get() {
            return l;
        }
    }
}
